package com.zbj.data.jpa.service.impl;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.zbj.data.jpa.entity.Teacher;
import com.zbj.data.jpa.repository.TeacherRepository;
import com.zbj.data.jpa.service.TeacherService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Collection;
import java.util.Date;
import java.util.List;


/**
 * TeacherServiceImpl
 *
 * @author weigang
 * @create 2017-09-13
 **/
@Service
public class TeacherServiceImpl implements TeacherService {

	@Autowired
	private TeacherRepository teacherRepository;

	@Autowired
	@PersistenceContext
	private EntityManager entityManager;

	@Override
	public Page<Teacher> findNoCriteria(Pageable pageable) {
		return teacherRepository.findAll(pageable);
	}

	@Override
	public Page<Teacher> findByNameLike(String name, Pageable pageable) {
		return teacherRepository.findAll(new Specification<Teacher>() {
			@Override
			public Predicate toPredicate(Root<Teacher> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
				return builder.and(Lists.newArrayList(builder.like(root.get("name"), "%" + name)).toArray(new Predicate[1]));
			}
		}, pageable);
	}

	@Override
	public Page<Teacher> findByDynamicQuery(String name, Date startDate, String addressLike, Collection<Integer> ages) {
		Specification<Teacher> specification = this.where(name, null, startDate, null, addressLike, ages);
		Pageable pageable = new PageRequest(0, 10, Sort.Direction.DESC, "id"); // 默认从0开始
		return teacherRepository.findAll(specification, pageable);
	}

	//////////////////////group by having start///////////////////////////////
	@Override
	public List<Object[]> groupByTeacherAsSql() {
		List<Object[]> list = entityManager.createNativeQuery("select address, count(*) from teacher group by address").getResultList();
		return list;
	}

	@Override
	public List<Object[]> groupByTeacherAsHql() {
		List<Object[]> list = entityManager.createQuery("select address, count(*) from Teacher group by address").getResultList();
		return list;
	}

	@Override
	public List<Object[]> groupByTeacherAsSpecification() {
		// 根据地址分组查询，并且老师数量大于3的所有地址
		CriteriaBuilder builder = entityManager.getCriteriaBuilder();
		CriteriaQuery<Object[]> query = builder.createQuery(Object[].class);
		Root<Teacher> root = query.from(Teacher.class);
		query.multiselect(root.get("address"), builder.count(root.get("id"))).groupBy(root.get("address")).having(builder.gt(builder.count(root.get("id")), 3));
		return entityManager.createQuery(query).getResultList();
	}
	//////////////////////group by having end///////////////////////////////

	private Specification<Teacher> where(final String name, final Integer age, Date startDate, Date endDate, String addressLike, Collection<Integer> ages) {
		return (root, query, builder) -> {
			List<Predicate> predicates = Lists.newArrayList();
			if (StringUtils.isNotBlank(name)) {
				predicates.add(builder.equal(root.get("name"), name.trim()));
			}

			if (!ObjectUtils.isEmpty(age)) {
				predicates.add(builder.equal(root.get("age"), age));
			}

			if (!ObjectUtils.isEmpty(startDate)) {
				predicates.add(builder.greaterThanOrEqualTo(root.get("createDate"), startDate));
			}

			if (!ObjectUtils.isEmpty(endDate)) {
				predicates.add(builder.lessThanOrEqualTo(root.get("createDate"), endDate));
			}

			if (StringUtils.isNotBlank(addressLike)) {
				predicates.add(builder.like(root.get("address"), "%" + addressLike + "%"));
			}

			if (CollectionUtils.isNotEmpty(ages)) {
				predicates.add(root.get("age").in(ages));
			}

			return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
		};
	}

	/**
	 * 始终走的是从库
	 *
	 * @param phone
	 * @param name
	 * @return
	 */
//	@Transactional("transactionManagerSecondary")
	@Override
	public int updateTeacherPhoneByName(String phone, String name) {
		Preconditions.checkArgument(StringUtils.isNotBlank(phone), "phone is not null");
		Preconditions.checkArgument(StringUtils.isNotBlank(name), "name is not null");
		return teacherRepository.updateTeacherPhoneByName(phone, name);
	}

	@Override
	public int updatePhoneByName(String phone, String name) {
		Preconditions.checkArgument(StringUtils.isNotBlank(phone), "phone is not null");
		Preconditions.checkArgument(StringUtils.isNotBlank(name), "name is not null");
		return teacherRepository.updatePhoneByName(phone, name);
	}

	@Override
	public int deletePhoneByName(String name) {
		Preconditions.checkArgument(StringUtils.isNotBlank(name), "name is not null");
		return teacherRepository.deletePhoneByName(name);
	}
}
